package com.gitee.booting.idem4j.util;

import com.gitee.booting.idem4j.properties.Idem4jProperties;
import lombok.extern.slf4j.Slf4j;

import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;

@Slf4j
public class JavaUtils {
    private static final Map<String, Supplier<String>> CACHE = new HashMap<>();
    public static final Idem4jProperties.Control DEFAULT = new Idem4jProperties.Control()
        .setGenerator(() -> java.util.UUID.randomUUID().toString());

    public static Supplier<String> build(String supplier) {
        if (!CACHE.containsKey(supplier)) {
            // Load and instantiate compiled class.
            try {
                JavaCompiler jc = ToolProvider.getSystemJavaCompiler();

                File idempotentSupplier = Paths.get("IdempotentSupplier.java").toFile();
                final FileOutputStream fos = new FileOutputStream(idempotentSupplier, false);
                String source = "public class IdempotentSupplier {" +
                    "  public static final java.util.function.Supplier<String> SUPPLIER = " + supplier + " ;" +
                    "}";
                fos.write(source.getBytes(StandardCharsets.UTF_8));
                fos.flush();
                fos.close();

                jc.run(System.in, System.out, System.err, idempotentSupplier.getAbsolutePath());
                URLClassLoader classLoader = URLClassLoader.newInstance(new URL[]{
                    new File(".").toURI().toURL()
                });
                Class<?> cls = Class.forName("IdempotentSupplier", true, classLoader);
                CACHE.put(supplier, (Supplier<String>) cls.getField("SUPPLIER").get(null));
            } catch (ClassNotFoundException | IllegalAccessException | NoSuchFieldException | IOException e) {
                log.error("Unable to compile custom supplier for {}", e.getMessage());
            }
        }

        return CACHE.getOrDefault(supplier, DEFAULT.getGenerator());
    }
}
